/*
 * Wazuh Vulnerability scanner - Scan Orchestrator
 * Copyright (C) 2015, Wazuh Inc.
 * March 11, 2024.
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General Public
 * License (version 2) as published by the FSF - Free Software
 * Foundation.
 */

#ifndef _CLEAN_INVENTORY_HPP
#define _CLEAN_INVENTORY_HPP

#include "chainOfResponsability.hpp"
#include "inventorySync.hpp"
#include "rocksDBWrapper.hpp"
#include "scanContext.hpp"

/**
 * @brief TCleanInventory class.
 * This class is in charge of cleaning the inventory database.
 * It is responsible for deleting all the inventory entries for all agents and affected component types.
 * It is also responsible to call a sub-orchestration to publish the changes to the indexer.
 * It receives the scan context and the inventory database and returns the scan context with the inventory cleaned.
 * The affected component type can be Os or Package.
 * Os: Delete inventory of the OS for all agents.
 * Package: Delete inventory of the package for all agents.
 * The sub-orchestration will be called with the context->m_elements populated with the operation and the element key.
 *
 * @tparam TScanContext scan context type.
 */
template<typename TScanContext = ScanContext,
         typename TAbstractHandler = AbstractHandler<std::shared_ptr<TScanContext>>>
class TCleanInventory final
    : public AbstractHandler<std::shared_ptr<TScanContext>>
    , public TInventorySync<TScanContext>
{
private:
    std::shared_ptr<TAbstractHandler> m_subOrchestration;

public:
    // LCOV_EXCL_START
    /**
     * @brief CleanInventory constructor.
     *
     * @param inventoryDatabase Inventory database.
     * @param subOrchestration Sub-orchestration to publish changes to the indexer.
     */
    explicit TCleanInventory(Utils::RocksDBWrapper& inventoryDatabase,
                             std::shared_ptr<TAbstractHandler> subOrchestration)
        : TInventorySync<TScanContext>(inventoryDatabase)
        , m_subOrchestration(std::move(subOrchestration))
    {
    }
    // LCOV_EXCL_STOP

    /**
     * @brief Handles request and passes control to the next step of the chain.
     *
     * @param data Scan context.
     * @return std::shared_ptr<ScanContext> Abstract handler.
     */
    std::shared_ptr<TScanContext> handleRequest(std::shared_ptr<TScanContext> data) override
    {
        for (const auto& type : {AffectedComponentType::Os, AffectedComponentType::Package})
        {
            TInventorySync<TScanContext>::m_inventoryDatabase.deleteAll(
                [&](const std::string& key, const std::string& value)
                {
                    // Extract the list of CVEs from the key
                    auto listCve = Utils::split(value, ',');

                    for (const auto& cve : listCve)
                    {
                        std::string elementKey;
                        elementKey.append(key);
                        elementKey.append("_");
                        elementKey.append(cve);

                        // We use elementKey as the id of the element, because it is unique.
                        auto context = std::make_shared<TScanContext>();
                        context->m_noIndex = data->m_noIndex;
                        context->m_elements.emplace(elementKey,
                                                    TInventorySync<TScanContext>::buildElement("DELETED", elementKey));
                        m_subOrchestration->handleRequest(std::move(context));
                    }

                    logDebug2(WM_VULNSCAN_LOGTAG, "Deleting all entries for key prefix: %s", key.c_str());
                },
                AFFECTED_COMPONENT_COLUMNS.at(type));
        }
        // Delete all for specific column.
        TInventorySync<TScanContext>::m_inventoryDatabase.deleteAll(OS_INITIAL_SCAN);

        return AbstractHandler<std::shared_ptr<TScanContext>>::handleRequest(std::move(data));
    }
};

using CleanInventory = TCleanInventory<>;

#endif // _CLEAN_INVENTORY_HPP
